package sk.naive.talker.util;

import java.net.*;
import java.util.logging.Logger;

/**
 * NondelegatingClassLoader.
 * <p>
 * Class loader works like URLClassLoader except for resources/classes with specified prefix.
 * These resources/classes are loaded always by this class loader with no delegation of this
 * work up to class loader's parent.
 * <p>
 * Then it's easy to drop this class loader (garbage collection) and create new one. This
 * is simple way how to reload classes or resources.
 *
 * @author <a href="mailto:virgo@naive.deepblue.sk">Richard "Virgo" Richter</a>
 * @version $Revision: 1.4 $ $Date: 2005/01/10 22:11:24 $
 */
public class NondelegatingClassLoader extends URLClassLoader {
	private String prefix;
	private Logger logger;

	public NondelegatingClassLoader(URL[] urls, String prefix, Logger logger) {
		super(urls);
		this.prefix = prefix;
		this.logger = logger;
	}

	public static NondelegatingClassLoader create(String pattern) {
		return new NondelegatingClassLoader(((URLClassLoader) ClassLoader.getSystemClassLoader()).getURLs(), pattern, null);
	}

	public static NondelegatingClassLoader create(String pattern, Logger logger) {
		return new NondelegatingClassLoader(((URLClassLoader) ClassLoader.getSystemClassLoader()).getURLs(), pattern, logger);
	}

	protected synchronized Class loadClass(String name, boolean resolve)
		throws ClassNotFoundException
	{
		Class klass = findLoadedClass(name);
		if (klass != null) {
			return klass;
		}
		if (prefix == null || name.startsWith(prefix)) {
			klass = super.findSystemClass(name);
			log("Delegating non-matching class: " + klass);
		} else {
			klass = findClass(name);
			log("Found matching class: " + klass);
		}
		if (resolve) {
			resolveClass(klass);
			log("Resolved: " + klass);
		}
		return klass;
	}

	public URL getResource(String name) {
		URL url;
		if (prefix == null || name.startsWith(prefix)) {
			url = super.getResource(name);
			log("Delegating non-matching resource: " + url);
		} else {
			url = findResource(name);
			log("Found matching resource: " + url);
		}
		return url;
	}

	private void log(String message) {
		if (logger != null) {
			logger.finer(message);
		}
	}

	/**
	 * Funkcne demo class reloadingu.
	 * <p>
	 * Je mozne si vsimnut, ze ziadna trieda nie je priamo zakompilovana, lebo inak by ju loadoval
	 * neziaduci class loader.
	 *
	 * @param args
	 * @throws Exception
	public static void main(String[] args) throws Exception {
		ClassLoader classLoader = createWithClasspath("sk\\.naive\\.talker\\..*");
		classLoader.loadClass("sk.naive.talker.util.Pokus").newInstance();
		System.in.read();
		classLoader.loadClass("sk.naive.talker.util.Pokus").newInstance();
		classLoader = createWithClasspath("sk\\.naive\\.talker\\..*");
		classLoader.loadClass("sk.naive.talker.util.Pokus").newInstance();
	}
	 */
}
